/********************************************************************************
 * CommonUtil.java
 *
 * Created by Jigar Mistry
 * Last modified Date: Aug 27, 2008 8:44:21 AM by Jigar Mistry
 * Version : 0.1
 * Copyright (c) 2008 - 2009 cyberThink Infotech Pvt. Ltd., All rights reserved.
 ********************************************************************************/

package com.printeverywhere.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.jasypt.util.text.BasicTextEncryptor;

import com.printeverywhere.delegator.CategoryManagerServiceDelegator;
import com.printeverywhere.delegator.CommonFunctionDelegator;
import com.printeverywhere.dto.GeneralCategoriesWOS;
import com.printeverywhere.dto.Languages;
import com.printeverywhere.dto.LocationCategoriesWOS;

/**
 * The Class CommonUtil.
 */
public class CommonUtil {

	/** Logger for this class. */
	private static final Logger logger = Logger.getLogger(CommonUtil.class);

	/** The Constant GETRANDOMPASSWORD_CHAR. */
	private static final String GETRANDOMPASSWORD_CHAR = "abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

	/**
	 * The method getRandomPassword generates random password from its length.
	 *
	 * @param length -
	 *            the length of the password to generate random.
	 *
	 * @return the random password generated.
	 *
	 * @author Jigar Mistry
	 */
	public static String getRandomValue(int length) {
		if (logger.isDebugEnabled()) {
			logger.debug("getRandomValue(int) - start"); //$NON-NLS-1$
		}

		StringBuffer buffer = new StringBuffer();
		Random random = new Random();
		char[] chars = GETRANDOMPASSWORD_CHAR.toCharArray();
		for (int i = 0; i < length; i++) {
			buffer.append(chars[random.nextInt(chars.length)]);
		}
		String returnString = buffer.toString();
		if (logger.isDebugEnabled()) {
			logger.debug("getRandomValue(int) - end"); //$NON-NLS-1$
		}
		return returnString;
	}

	/**
	 * Encrypts the given data by basic text encryptor.
	 *
	 * @param data
	 *            the data to encrypt.
	 *
	 * @return the encrypted string.
	 *
	 * @author Jigar Mistry
	 */
	public static String encrypt(String data) {
		if (logger.isDebugEnabled()) {
			logger.debug("encrypt(String) - start"); //$NON-NLS-1$
		}

		BasicTextEncryptor encryptor = new BasicTextEncryptor();
		encryptor.setPassword(AttributeConstants.KEY);
		data = encryptor.encrypt(data);
		data = patternReplace(data, AttributeConstants.ENCRYPTION_PATTERN_GPSG,
				AttributeConstants.GPSG);
		data = patternReplace(data, AttributeConstants.ENCRYPTION_PATTERN_GELG,
				AttributeConstants.GELG);
		data = patternReplace(data, AttributeConstants.ENCRYPTION_PATTERN_GSLG,
				AttributeConstants.GSLG);

		if (logger.isDebugEnabled()) {
			logger.debug("encrypt(String) - end"); //$NON-NLS-1$
		}
		return data;
	}

	/**
	 * Decrypts the given data by basic text encryptor.
	 *
	 * @param data
	 *            the data to encrypt.
	 *
	 * @return the decrypted string.
	 *
	 * @throws EncryptionOperationNotPossibleException
	 *             the encryption operation not possible exception
	 *
	 * @author Jigar Mistry
	 */
	public static String decrypt(String data)
			throws EncryptionOperationNotPossibleException {
		if (logger.isDebugEnabled()) {
			logger.debug("decrypt(String) - start"); //$NON-NLS-1$
		}

		BasicTextEncryptor encryptor = new BasicTextEncryptor();
		encryptor.setPassword(AttributeConstants.KEY);
		data = patternReplace(data, AttributeConstants.GPSG,
				AttributeConstants.PLUS);
		data = patternReplace(data, AttributeConstants.GELG,
				AttributeConstants.EQUALS);
		data = patternReplace(data, AttributeConstants.GSLG,
				AttributeConstants.SLASH);
		String returnString = encryptor.decrypt(data);
		if (logger.isDebugEnabled()) {
			logger.debug("decrypt(String) - end"); //$NON-NLS-1$
		}
		return returnString;
	}

	/**
	 * The method patternReplace replaces the text, matches the text for regular
	 * expression regex if matches than replaces by replace string.
	 *
	 * @param text
	 *            the text to be matched.
	 * @param regex
	 *            the regex is regular expression for matching with text.
	 * @param replaceString
	 *            the replacestring replaces the text if it matches the pattern.
	 *
	 * @return the string replaced by replacestring if matched else returns
	 *         text.
	 */
	@SuppressWarnings("unused")
	private static String patternReplace(String text, String regex,
			String replaceString) {
		if (logger.isDebugEnabled()) {
			logger.debug("patternReplace(String, String, String) - start"); //$NON-NLS-1$
		}

		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(text);
		String returnString = matcher.replaceAll(replaceString);
		if (logger.isDebugEnabled()) {
			logger.debug("patternReplace(String, String, String) - end"); //$NON-NLS-1$
		}
		return returnString;
	}

	public static String getCountryCodeByIP(String ip) {
		StringBuffer content = new StringBuffer();

		try {
			URL url = new URL("http://api.hostip.info/country.php?ip=" + ip);
			BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));

			String inputLine;

			while ((inputLine = in.readLine()) != null)
				content.append(inputLine);

			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return content.toString();
	}

	public static boolean isImage(byte[] imagearray) throws NullPointerException {
		try {
			return ImageIO.read(new ByteArrayInputStream(imagearray)) != null;
		} catch (IOException e) {
			logger.error(e);
			return false;
		}
	}

	public static byte[] getBytesFromFile(File file) throws IOException,NullPointerException {
		InputStream is = new FileInputStream(file);

		// Get the size of the file
		long length = file.length();


		// Create the byte array to hold the data

		byte[] bytes = new byte[Integer.parseInt(Long.toString(length))];

		// Read in the bytes
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		// Ensure all the bytes have been read in
		if (offset < bytes.length) {
			throw new IOException("Could not completely read file "
					+ file.getName());
		}

		// Close the input stream and return bytes
		is.close();
		return bytes;
	}

	public static String getDefaultLanguage(List<Languages> languages) {
		String langCode = "en";

		for (Languages language : languages) {
			if(language.getDefault_())
				langCode = language.getLanguageCode();
		}

		return langCode;
	}

	public static Languages getDefaultLanguages(List<Languages> languages) {
		Languages lang = new Languages("en" , "English" , true,true);
		for (Languages language : languages) {
			if(language.getDefault_()){
				lang= language;
			}
		}
		return lang;
	}

	public static String getLocalBasePath(HttpServletRequest request) {
		return new StringBuffer(request.getScheme()).append("://").append(request.getServerName()).append(":").append(request.getServerPort()).append(request.getContextPath()).toString();
	}

	/**
	 * The method getURLContent returns String path if the given path is valid.
	 *
	 * @param path
	 *            the string value for path is checked for available location
	 *
	 * @return the uRL content gives string path if location is valid else
	 *         returns blank.
	 * @author Jigar Mistry
	 */
	public static String getURLContent(String path) {

		HostnameVerifier hv = new HostnameVerifier()
		{
			public boolean verify(String hostname, SSLSession session) {
				return true;
			}
		};

		InputStream inputStream = null;
		try {
			URL url = new URL(path);

			if(path.startsWith("https")) {
				trustAllHttpsCertificates();
				HttpsURLConnection.setDefaultHostnameVerifier(hv);
				HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
				inputStream = conn.getInputStream();
			} else {
				URLConnection conn = url.openConnection();
				inputStream = conn.getInputStream();
			}
		} catch (MalformedURLException malformedURLException) {
			logger.error(malformedURLException);
		} catch (IOException ioException) {
			logger.error(ioException);
		} catch (Exception exception) {
			logger.error(exception);
		}

		return inputStream != null ? convertInputStreamToString(inputStream) : "";
	}

	/**
	 * This method validates all the HTTPS certificates.
	 *
	 * @throws Exception
	 */
	private static void trustAllHttpsCertificates() throws Exception
	{
		//  Create a trust manager that does not validate certificate chains:
		javax.net.ssl.TrustManager[] trustAllCerts =
		new javax.net.ssl.TrustManager[1];
		javax.net.ssl.TrustManager tm = new miTM();
		trustAllCerts[0] = tm;
		javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
		sc.init(null, trustAllCerts, null);
		javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(
		sc.getSocketFactory());
	}

	public static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
		public java.security.cert.X509Certificate[] getAcceptedIssuers() {
			return null;
		}

		public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
			return true;
		}

		public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
			return true;
		}

		public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
				throws java.security.cert.CertificateException {
			return;
		}

		public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
				throws java.security.cert.CertificateException {
			return;
		}
	}

	/**
	 * The method convertInputStreamToString Converts inputStream to string.
	 *
	 * @param inputStream
	 *            the inputstream that is to be converted in string.
	 *
	 * @return the string of the inputstream.
	 * @author Jigar Mistry
	 */
	private static String convertInputStreamToString(InputStream inputStream) {
		String line = null;
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
		StringBuffer buffer = new StringBuffer();

		try {
			while ((line = in.readLine()) != null) {
				buffer.append(line);
			}
		} catch (IOException ioException) {
			logger.error(ioException);
		}
		return buffer.toString();
	}

	public static String removeChar(String string, char character) {
		String result = "";
		for (int index = 0; index < string.length(); index ++) {
			if (string.charAt(index) != character) result += string.charAt(index);
		}
		return result;
	}


	// Call a method of an object with no arguments/parameters.
	public static Object callMethod(Class c, Object obj, String methodName) {
		Object result = null;
		try {
		Method m = c.getMethod(methodName, new Class[]{});
		result = m.invoke(obj, new Object[]{} );
		}
		catch(java.lang.NoSuchMethodException e) {
			System.out.println("Error - No such method: \n" + e.getMessage());
		}
		catch(java.lang.IllegalAccessException e) {
			System.out.println("Error - Illegal access: \n" + e.getMessage());
		}
		catch (java.lang.reflect.InvocationTargetException e) {
			System.out.println("Error - Reflection error : \n" + e.getMessage());
		}
		return result;
	}

	public static Object setValue(Class c, Object obj, String methodName, String value) {
		Field urlField;
		Object result = null;
		try {
			urlField = c.getField(methodName);
			urlField.set(obj, value);
		}
		catch(java.lang.IllegalAccessException e) {
			System.out.println("Error - Illegal access: \n" + e.getMessage());
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}

		return result;
	}

	public static Object setIntValue(Class c, Object obj, String methodName, int value) {
		Field urlField;
		Object result = null;
		try {
			Field[] fields = c.getFields();

			for (Field field : fields) {
				System.out.println(field.getName());
			}

			urlField = c.getField(methodName);
			urlField.set(obj, value);
		}
		catch(java.lang.IllegalAccessException e) {
			System.out.println("Error - Illegal access: \n" + e.getMessage());
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}

		return result;
	}

	public static boolean isContainsBannedWords(String[] words, String content) {
		if(words.length == 0)
			return true;

		for (String word : words) {
			Pattern pattern = Pattern.compile(word);
	        Matcher matcher = pattern.matcher(content);

	        if (matcher.find()) {
	        	return true;
			}
		}

		return false;
	}

	public static String getChildrensHierarchy(GeneralCategoriesWOS cid) {
		StringBuffer childrenList = new StringBuffer();
		int minLevel = cid.getLevel();
		int maxLevel = cid.getLevel();

		List list = CommonFunctionDelegator.executeSQLQuery("SELECT max(level) FROM general_categories WHERE mainparentid = " + cid.getMainParentId());
		if(list != null) {
			maxLevel = Integer.parseInt(list.get(0).toString());
		}

		if(minLevel == maxLevel)
			return String.valueOf(cid.getCategoryId());

		StringBuffer leftJoin = new StringBuffer();
		leftJoin.append("SELECT t").append(maxLevel - 1).append(".categoryId FROM general_categories AS t").append(minLevel - 1);

		for (int index = minLevel; index < maxLevel; index++) {
			leftJoin.append(" LEFT JOIN general_categories AS t").append(index).append(" ON t").append(index).append(".parentcategoryid = t").append(index - 1).append(".categoryid ");
		}

		leftJoin.append("WHERE t").append(minLevel - 1).append(".categoryId = ").append(cid.getCategoryId());
		System.out.println(leftJoin.toString());
		list = CommonFunctionDelegator.executeSQLQuery(leftJoin.toString());
		if(list != null && list.size() > 0) {
			for (Object object : list) {
				if (object != null) {
					childrenList.append(object.toString()).append(",");
				}
			}
		}

		if (childrenList.length() == 0) {
			return String.valueOf(cid.getCategoryId());
		}

		if (childrenList.toString().length() > 1) {
			return childrenList.substring(0, childrenList.length() - 1);
		} else {
			return childrenList.toString();
		}
	}

	public static String getLocationChildrensHierarchy(LocationCategoriesWOS lid) {
		StringBuffer childrenList = new StringBuffer();
		int minLevel = lid.getLevel();
		int maxLevel = lid.getLevel();

		List list = CommonFunctionDelegator.executeSQLQuery("SELECT max(level) FROM location_categories WHERE mainparentid = " + lid.getMainParentId());
		if(list != null) {
			maxLevel = Integer.parseInt(list.get(0).toString());
		}

		if(minLevel == maxLevel)
			return String.valueOf(lid.getCategoryId());

		StringBuffer leftJoin = new StringBuffer();
		leftJoin.append("SELECT t").append(maxLevel - 1).append(".categoryId FROM location_categories AS t").append(minLevel - 1);

		for (int index = minLevel; index < maxLevel; index++) {
			leftJoin.append(" LEFT JOIN location_categories AS t").append(index).append(" ON t").append(index).append(".parentcategoryid = t").append(index - 1).append(".categoryid ");
		}

		leftJoin.append("WHERE t").append(minLevel - 1).append(".categoryId = ").append(lid.getCategoryId());
		System.out.println(leftJoin.toString());
		list = CommonFunctionDelegator.executeSQLQuery(leftJoin.toString());
		if(list != null && list.size() > 0) {
			for (Object object : list) {
				if (object != null) {
					childrenList.append(object.toString()).append(",");
				}
			}
		}

		if (childrenList.length() == 0) {
			return String.valueOf(lid.getCategoryId());
		}

		if (childrenList.toString().length() > 1) {
			return childrenList.substring(0, childrenList.length() - 1);
		} else {
			return childrenList.toString();
		}
	}

	/**
	 * The main method.
	 *
	 * @param args
	 *            the arguments
	 */
	public static void main(String[] args) {
		if (logger.isDebugEnabled()) {
			logger.debug("main(String[]) - start"); //$NON-NLS-1$
		}

		System.out.println(getChildrensHierarchy(CategoryManagerServiceDelegator.getWOS(87)));

		if (logger.isDebugEnabled()) {
			logger.debug("main(String[]) - end"); //$NON-NLS-1$
		}
	}
}